# -*- coding: utf-8 -*-            
# @Time : 2022/11/18 15:53
# @Author  : lining
# @FileName: 机器人走路.py
"""
https://leetcode.cn/problems/walking-robot-simulation/
机器人在一个无限大小的 XY 网格平面上行走，从点 (0, 0) 处开始出发，面向北方。该机器人可以接收以下三种类型的命令 commands ：

-2 ：向左转 90 度
-1 ：向右转 90 度
1 <= x <= 9 ：向前移动 x 个单位长度
在网格上有一些格子被视为障碍物 obstacles 。第 i 个障碍物位于网格点  obstacles[i] = (xi, yi) 。

机器人无法走到障碍物上，它将会停留在障碍物的前一个网格方块上，但仍然可以继续尝试进行该路线的其余部分。

返回从原点到机器人所有经过的路径点（坐标为整数）的最大欧式距离的平方。（即，如果距离为 5 ，则返回 25 ）
输入：commands = [4,-1,3], obstacles = []
输出：25
解题思路
（1）网格行走题目技巧，使用方向数组
（2）上下左右四个方向使用0，1，2，3进行编号，要走的步数用0，1，-1表示，和方向对应起来，这样可以用下标直接获取下一步要走的x，y各自的步数
（3）每次只走一步，先获取下一步要走的位置，判断有没有障碍，没有就走，有就停止
（4）因为指令可能有很多步，使用数组存储指令，判断下一步的位置有没有障碍物会很慢，
要转为map类型的数据（根据值查找，数组是根据下标查找的时间复杂度为O(1)）
"""
import time


class Solution:
    def robotSim(self, commands, obstacles):
        a = time.perf_counter()
        # 存储x*x=y*y
        ans = []
        # obstacles可能会很大， 需要转set，set底层是个hashtable，查找效率高于列表
        obs = set([','.join([str(i[0]), str(i[1])]) for i in obstacles])
        # 初始位置
        x = 0
        y = 0
        # 横坐标需要走的步数，[上，右, 下，左]
        x_step = [0, 1, 0, -1]
        # 纵坐标需要走的步数，[上，右, 下，左]
        y_step = [1, 0, -1, 0]
        # 方向初始为0，根据方向计算x,y分别需要走的步数,北：0，东：1，南:2, 西：3
        dir = 0
        for command in commands:
            # 初始位置在(0,0)初始方向为0，向北，如果右转，就转向东边，位置加1，取到要走的步数（x+1，y+0）
            if command == -1:
                dir = (dir + 1) % 4
            elif command == -2:
                dir = (dir + 3) % 4
            else:
                for i in range(command):
                    # 下一步要走的位置
                    next_x = x+x_step[dir]
                    next_y = y + y_step[dir]
                    # 列表不能直接hash
                    new_node = str(next_x)+','+str(next_y)
                    # 判断下一步的位置有没有障碍物，障碍物就不用走了，不是障碍物就继续前进
                    if new_node in obs:
                        break
                    x = next_x
                    y = next_y
                    print(x,y)
                    ans.append(x*x+y*y)
        print(ans)
        print(max(ans))
        print(time.perf_counter()-a)


"""
问题：hash的方法使用的是将字符串进行hash，对字符串进行hash时，需要扫描每一个字符，执行就会很慢
改进：将二维数组改成一维数组，转成一个int，对int进行hash
将一个二维的表格，转成一个一维的左下角是(0,0)开始，位置(2,3)就是2x列数+3
"""
class Solution1:
    def robotSim(self, commands, obstacles):
        a = time.perf_counter()
        # 存储x*x=y*y
        ans = []
        # obstacles可能会很大， 需要转set，set底层是个hashtable，查找效率高于列表
        obs = self.my_set(obstacles)
        # 初始位置
        x = 0
        y = 0
        # 横坐标需要走的步数，[上，右, 下，左]
        x_step = [0, 1, 0, -1]
        # 纵坐标需要走的步数，[上，右, 下，左]
        y_step = [1, 0, -1, 0]
        # 方向初始为0，根据方向计算x,y分别需要走的步数,北：0，东：1，南:2, 西：3
        dir = 0
        for command in commands:
            # 初始位置在(0,0)初始方向为0，向北，如果右转，就转向东边，位置加1，取到要走的步数（x+1，y+0）
            if command == -1:
                dir = (dir + 1) % 4
            elif command == -2:
                dir = (dir + 3) % 4
            else:
                for i in range(command):
                    # 下一步要走的位置
                    next_x = x+x_step[dir]
                    next_y = y + y_step[dir]
                    # 列表不能直接hash
                    new_node = (30000+next_x)*60001+next_y
                    # 判断下一步的位置有没有障碍物，障碍物就不用走了，不是障碍物就继续前进
                    if new_node in obs:
                        break
                    x = next_x
                    y = next_y
                    print(x,y)
                    ans.append(x*x+y*y)
        print(ans)
        print(max(ans))
        print(time.perf_counter()-a)

    def my_set(self, my_list):
        return set([(30000+i[0])*60001+i[1] for i in my_list])


commands = [4,-1, 4,-2,4]
obstacles = [[2,4]]
Solution().robotSim(commands, obstacles)
